package genericorderedlist;

import java.lang.reflect.InvocationTargetException;
import java.util.Comparator;
import java.util.Iterator;
import java.util.ListIterator;

public class GenericOrderedList<E> implements OrderedList<E> {
	private final java.util.List<E> list;
	private final Comparator<? super E> cmp;
	
	public static class Builder<E> {
		private java.util.List<E> list = new java.util.LinkedList<>();
		private Comparator<? super E> cmp;
		@SuppressWarnings("unchecked")
		private Iterator<? extends E> it = (Iterator<? extends E>)java.util.Arrays.asList().iterator();
		
		public Builder(Comparator<? super E> cmp) {
			this.cmp = cmp;
		}
		
		
		
		public Builder<E> list(@SuppressWarnings("rawtypes") Class<? extends java.util.List> listType) throws InstantiationException, 
																				IllegalAccessException, 
																				IllegalArgumentException, 
																				InvocationTargetException, 
																				NoSuchMethodException, 
																				SecurityException {
			@SuppressWarnings("unchecked")
			java.util.List<E> thelist = (java.util.List<E>)listType.getConstructor().newInstance();
			list = thelist;
			return this;
		}
		
		public Builder<E> iterator(Iterator<? extends E> it) {
			if (it == null)
				throw new NullPointerException();
			this.it = it;
			return this;
		}
		
		public GenericOrderedList<E> build() {
			return new GenericOrderedList<>(this);
		}
	}
	
	public static class NatOrderBuilder<E extends Comparable<? super E>> extends Builder<E> {
		public NatOrderBuilder() {
			super(ListUtil.<E>naturalOrder());
		}
		
		public NatOrderBuilder<E> list(@SuppressWarnings("rawtypes") Class<? extends java.util.List> listType) 
																					throws InstantiationException,
																							IllegalAccessException, 
																							IllegalArgumentException, 
																							InvocationTargetException, 
																							NoSuchMethodException, 
																							SecurityException {
			super.list(listType);
			return this;
		}
		
		public NatOrderBuilder<E> iterator(Iterator<? extends E> it) {
			super.iterator(it);
			return this;
		}
	}
	
	private GenericOrderedList(Builder<E> builder) {
		this.list = builder.list;
		this.cmp = builder.cmp;
		
		while(builder.it.hasNext())
			add(builder.it.next());
	}
	

	@Override
	public boolean contains(E e) {
		return ListUtil.contains(cmp, this, e);
	}

	@Override
	public E get(int index) {
		return list.get(index);
	}

	@Override
	public Iterator<E> iterator() {
		return list.iterator();
	}

	@Override
	public ListIterator<E> listIterator() {
		return list.listIterator();
	}

	@Override
	public ListIterator<E> listIterator(int size) {
		return list.listIterator(size);
	}

	@Override
	public boolean remove(E e) {
		return ListUtil.remove(cmp, this, e);
	}

	@Override
	public int size() {
		return list.size();
	}

	@Override
	public int compareTo(OrderedList<? extends E> o) {
		return ListUtil.compareTo(cmp, this, o);
	}

	@Override
	public boolean add(E e) {
		return ListUtil.add(cmp, this, e);
	}

	@Override
	public boolean addAll(Iterable<E> o1) {
		return ListUtil.addAll(cmp, o1, this);
	}

	@Override
	public Comparator<? super E> getComparator() {
		return cmp;
	}


	@Override
	public String toString() {
		return list.toString();
	}
	
	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof OrderedList<?>))
			return false;
		GenericOrderedList<?> l = (GenericOrderedList<?>) obj;
		return cmp.equals(l.getComparator())
				&& ListUtil.equals(this, l);
	}
	
	public int hashCode() {
		return list.hashCode();
	}


}
